"""
预览操作模块
- 提供将音频片段导出到临时文件并调用系统播放器进行预览的功能
- 支持对编辑/合并等操作的预览，不落盘最终结果，只用于即时试听
"""

import tempfile
import platform
import subprocess
import os
from pydub import AudioSegment
from typing import List, Callable, Any, Optional, Union
from .base_audio import load_audio
from .edit_ops import (
    cut_audio as _cut,
    remove_segment as _remove,
    reverse_audio as _reverse,
    adjust_volume as _vol,
    change_speed as _speed,
    fade_in as _fade_in,
    fade_out as _fade_out,
    add_silence as _add_silence,
)
from .merge_ops import merge_audios as _merge, merge_audios_with_gaps as _merge_gaps


AudioLike = Union[str, AudioSegment]


def preview_audio(audio_data_or_path: AudioLike, start_ms: int = 0, duration_ms: Optional[int] = None) -> None:
    """
    预览音频或音频片段

    参数:
        audio_data_or_path: 音频对象或路径
        start_ms: 起始毫秒
        duration_ms: 预览时长（可选）
    """
    audio = load_audio(audio_data_or_path) if isinstance(audio_data_or_path, str) else audio_data_or_path
    if duration_ms:
        audio = audio[start_ms:start_ms + duration_ms]
    elif start_ms > 0:
        audio = audio[start_ms:]

    with tempfile.NamedTemporaryFile(delete=False, suffix='.wav') as temp_file:
        temp_path = temp_file.name

    audio.export(temp_path, format="wav")

    system = platform.system()
    try:
        if system == 'Darwin':
            subprocess.Popen(['afplay', temp_path])
        elif system == 'Windows':
            os.startfile(temp_path)  # type: ignore[attr-defined]
        elif system == 'Linux':
            subprocess.Popen(['aplay', temp_path])
    except Exception as e:
        print(f"预览音频时出错: {e}")


def preview_operation(input_paths: Union[str, List[str]], operation_func: Callable[..., Any], *args, **kwargs) -> None:
    """
    预览指定编辑/合并操作的处理结果（不写入到最终文件）

    参数:
        input_paths: 单个路径或路径列表
        operation_func: 目标操作函数（引用 edit_ops/merge_ops 的方法）
        *args, **kwargs: 传递给目标操作的参数
    """
    audio_result: Optional[AudioSegment] = None

    if operation_func is _cut:
        audio = load_audio(input_paths)  # type: ignore[arg-type]
        start_ms, end_ms = args[0], args[1]
        audio_result = audio[start_ms:end_ms]

    elif operation_func is _remove:
        audio = load_audio(input_paths)  # type: ignore[arg-type]
        start_ms, end_ms = args[0], args[1]
        audio_result = audio[:start_ms] + audio[end_ms:]

    elif operation_func in (_merge, _merge_gaps):
        paths = input_paths if isinstance(input_paths, list) else [input_paths]  # type: ignore[list-item]
        if not paths:
            return
        audio_result = load_audio(paths[0])
        for i, p in enumerate(paths[1:], 1):
            if operation_func is _merge_gaps:
                gaps_ms = args[0] if args else None
                if gaps_ms and i - 1 < len(gaps_ms) and gaps_ms[i - 1] > 0:
                    audio_result += AudioSegment.silent(duration=gaps_ms[i - 1])
            audio_result += load_audio(p)

    elif operation_func is _add_silence:
        audio = load_audio(input_paths)  # type: ignore[arg-type]
        position_ms, duration_ms = args[0], args[1]
        silence = AudioSegment.silent(duration=duration_ms)
        audio_result = audio[:position_ms] + silence + audio[position_ms:]

    elif operation_func is _reverse:
        audio_result = load_audio(input_paths).reverse()  # type: ignore[arg-type]

    elif operation_func is _vol:
        audio = load_audio(input_paths)  # type: ignore[arg-type]
        audio_result = audio + args[0]

    elif operation_func is _speed:
        audio = load_audio(input_paths)  # type: ignore[arg-type]
        speed_factor = args[0]
        audio_result = audio._spawn(audio.raw_data, overrides={
            "frame_rate": int(audio.frame_rate * speed_factor)
        }).set_frame_rate(audio.frame_rate)

    elif operation_func is _fade_in:
        audio = load_audio(input_paths)  # type: ignore[arg-type]
        audio_result = audio.fade_in(args[0])

    elif operation_func is _fade_out:
        audio = load_audio(input_paths)  # type: ignore[arg-type]
        audio_result = audio.fade_out(args[0])

    if audio_result:
        preview_audio(audio_result)